iT邦幫忙

2022 iThome 鐵人賽

DAY 12
0
自我挑戰組

嘗試30天學「不」會Rust系列 第 12

[Rust] 常用集合-字串 (string)

  • 分享至 

  • xImage
  •  

環境

OS: Windows 10
Editor: Visual Studio Code
Rust version: 1.63.0

再訪字串

先前有一篇有比較過Rust中的String與string literal。本篇以集合的角度來理解字串。

用集合的角度來想的話,字串其實就是字符的序列,下面開始介紹字串的常見操作。

字串(string)

Rust有直接支援UTF-8,所以這樣可以直接印出表情符號:

// 這會印出三杯馬丁尼
let martini_emoji = String::from("\u{1F378}\u{1F378}\u{1F378}");
println!("{}", martini_emoji);

建立

之前使用過這個方法建立字串:

let s = String.from("hello, world");

也可以使用這樣的方法建立:

let s = "hello, world".to_string();

將string literal 轉成 String

加入

幾種常見的方法更新字串的內容:

let mut s = "Hello".to_string();

// 加入字符
s.push(',');

// 加入string literal
s.push_str(" everyone!");

// 利用`format!()` 巨集
let hello_world = format!("{s} Nice to meet you");

println!("{}", hello_world);

還有一個是使用符號+來串接:

let s1 = String::from("tic");
let s2 = String::from("tac");
let s3 = String::from("toe");

let s = s1 + "-" + &s2 + "-" + &s3;

可以發現到s1的所有權變到s身上,然後s2s3使用借用的形式,如果把他們嘗試輸出

Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0382]: borrow of moved value: `s1`
   --> src\main.rs:21:20
    |
14  |     let s1 = String::from("tic");
    |         -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
...
18  |     let s = s1 + "-" + &s2 + "-" + &s3;
    |             -------- `s1` moved due to usage in operator
...
21  |     println!("{}", s1);
    |                    ^^ value borrowed here after move
    |
note: calling this operator moves the left-hand side
   --> C:\Users\User\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\core\src\ops\arith.rs:114:12
    |
114 |     fn add(self, rhs: Rhs) -> Self::Output;
    |            ^^^^
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0382`.

會標示s已經無效了。

s1s2會是借用的原因主要來源於+的泛型實作,參考來源於官方文件,點進去裏頭,除了看得懂十座許多泛型以外,還看到有許多沒看過的語法跟用詞,先列下來,早晚會再次碰到(挖坑~挖坑~):

  1. trait是甚麼?
  2. impl<'_>是甚麼意思?

清除

let s = String::from("Good night.");

// 清除
s.clear();

雖說已經是清除了,但原本佔據的大小(capacity)不會變更

let mut s = String::from("Good night.");

println!("string capacity is {}", s.capacity());
// 清除
s.clear();
println!("string capacity is {}", s.capacity());

當然也有remove的功能,填入索引(index)刪除字符,但要注意!如果索引超出範圍,程式會直接panic

let mut s = String::from("Good night.");
let end = s.remove(s.len() - 1);
println!("{}", end);

s.remove(12); // PANIC!

索引

雖說前面有提到可以把字串視為字符的序列集合,但是Rust的字串不允許使用[]進行字符的索引。

let s = String::from("Good night.");
let end = &s[s.len() - 1];

以下是輸出

Compiling basic v0.1.0 (D:\projects\rust_learning\basic)
error[E0277]: the type `String` cannot be indexed by `usize`
 --> src\main.rs:3:16
  |
3 |     let end = &s[s.len() - 1];
  |                ^^^^^^^^^^^^^^ `String` cannot be indexed by `usize`
  |
  = help: the trait `Index<usize>` is not implemented for `String`
  = help: the following other types implement trait `Index<Idx>`:
            <String as Index<RangeFrom<usize>>>
            <String as Index<RangeFull>>
            <String as Index<RangeInclusive<usize>>>
            <String as Index<RangeTo<usize>>>
            <String as Index<RangeToInclusive<usize>>>
            <String as Index<std::ops::Range<usize>>>
            <str as Index<I>>

For more information about this error, try `rustc --explain E0277`.

可以看到不給使用[],如果是上面的例子的話,會覺得納悶為什麼Rust不給這樣使用,原因最開始講的,Rust預設支援UTF-8,假如像最開始印出三杯馬丁尼,那使用索引取出某個位置的字符便會出現問題。

let martini_emoji = String::from("\u{1F378}\u{1F378}\u{1F378}");

所以在字串上,不能使用[]取指定某個位置的字符,但是可以使用切片(slice)取出string literal,但如果以馬丁尼的例子來看,也是要小心切片的位置可能構不成一個表情符號

let martini_emoji = String::from("\u{1F378}\u{1F378}\u{1F378}");
let martini = &martini_emoji[0..2];
println!("{}", martini);

輸出:

thread 'main' panicked at 'byte index 2 is not a char boundary; it is inside '?' (bytes 0..4) of `???`', library\core\src\str\mod.rs:127:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: process didn't exit successfully: `target\debug\basic.exe` (exit code: 101)

compiler很好心的告訴你,哪裡到哪裡可以形成一個表情符號:

// SUCCESS
let martini_emoji = String::from("\u{1F378}\u{1F378}\u{1F378}");
let martini = &martini_emoji[0..4];
println!("{}", martini);

Reference


上一篇
[Rust] 常見集合 - 動態陣列 (vector)
下一篇
[Rust] 常用集合 - 雜湊表(Hash Map)
系列文
嘗試30天學「不」會Rust18
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言